package cn.song.freight.controller;

import cn.hutool.json.JSONUtil;
import cn.song.freight.domain.dto.OperationLogQueryDTO;
import cn.song.freight.domain.entity.OperationLogDO;
import cn.song.freight.domain.result.PageUtils;
import cn.song.freight.domain.result.R;
import cn.song.freight.domain.vo.OperationLogStatisticsVO;
import cn.song.freight.domain.vo.OperationStatisticsVO;
import cn.song.freight.domain.vo.OperatorStatisticsVO;
import cn.song.freight.service.OperationLogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
 * 操作日志管理控制器
 * <pre>
 * 该控制器管理系统的操作日志功能，提供日志查询、统计分析和管理功能。
 * 支持多维度的日志查询和数据分析，为系统运营和审计提供数据支持。
 *
 * 核心功能：
 * - 操作日志的条件查询和分页查询
 * - 链路追踪功能，查看完整操作链路
 * - 操作统计分析和报表功能
 * - 业务数据的操作历史追踪
 * - 系统运营数据监控
 *
 * 查询维度：
 * - 按模块类型查询：区域管理、运费策略、定价配置等
 * - 按操作类型查询：新增、修改、删除、批量操作等
 * - 按操作人查询：特定用户的操作记录
 * - 按时间范围查询：指定时间段内的操作记录
 * - 按业务ID查询：特定业务数据的操作历史
 *
 * @author SongRenShuo
 * @version 1.0.0
 * @since 2025-08-29
 */
@Slf4j
@Validated
@RestController
@RequestMapping("/operation-log")
@Api(tags = "操作日志管理")
@RequiredArgsConstructor
public class OperationLogController {

    /**
     * 操作日志管理服务，处理业务逻辑
     */
    private final OperationLogService operationLogService;

    /**
     * 查询操作日志列表（分页）
     * <pre>
     * 此端点根据提供的查询参数检索操作日志列表。
     * 支持按模块类型、操作类型、操作人、时间范围等多种条件进行过滤，
     * 查询结果按操作时间倒序排列，支持分页查询。
     *
     * @param queryDTO 操作日志查询数据传输对象，包含查询条件和分页参数
     * @return 符合条件的分页操作日志列表
     */
    @PostMapping("/list")
    @ApiOperation("查询操作日志列表（分页）")
    public R<PageUtils<OperationLogDO>> listOperationLogs(@Valid @RequestBody OperationLogQueryDTO queryDTO) {
        log.info("查询操作日志，过滤条件: {}", JSONUtil.toJsonStr(queryDTO));

        PageUtils<OperationLogDO> pageResult = operationLogService.listOperationLogs(queryDTO);

        log.info("找到 {} 条符合条件的操作日志，当前页: {}/{}",
                pageResult.getTotalSize(), pageResult.getCurrentPage(), pageResult.getTotalPages());
        return R.success("操作日志查询成功", pageResult);
    }

    /**
     * 根据链路追踪ID查询相关操作日志
     * <pre>
     * 此端点根据链路追踪ID查询同一次操作中的所有日志记录，
     * 用于追踪完整的操作链路和业务流程。
     *
     * @param traceId 链路追踪ID
     * @return 相关的操作日志列表
     */
    @PostMapping("/trace/{traceId}")
    @ApiOperation("根据链路追踪ID查询相关操作日志")
    public R<List<OperationLogDO>> listOperationLogsByTraceId(
            @ApiParam("链路追踪ID") @PathVariable String traceId) {
        log.info("根据链路追踪ID查询操作日志: {}", traceId);

        List<OperationLogDO> operationLogs = operationLogService.listOperationLogsByTraceId(traceId);

        log.info("找到 {} 条链路追踪相关的操作日志", operationLogs.size());
        return R.success("链路追踪查询成功", operationLogs);
    }

    /**
     * 根据业务ID查询相关操作日志
     * <pre>
     * 此端点根据业务ID查询相关的操作日志，用于追踪特定业务数据的操作历史。
     * 支持单个业务ID或批量业务ID查询。
     *
     * @param businessId 业务ID
     * @param moduleType 模块类型，可选参数用于缩小查询范围
     * @return 相关的操作日志列表
     */
    @PostMapping("/business/{businessId}")
    @ApiOperation("根据业务ID查询相关操作日志")
    public R<List<OperationLogDO>> listOperationLogsByBusinessId(
            @ApiParam("业务ID") @PathVariable String businessId,
            @ApiParam("模块类型") @RequestParam(required = false) String moduleType) {
        log.info("根据业务ID查询操作日志: businessId={}, moduleType={}", businessId, moduleType);

        List<OperationLogDO> operationLogs = operationLogService.listOperationLogsByBusinessId(businessId, moduleType);

        log.info("找到 {} 条业务相关的操作日志", operationLogs.size());
        return R.success("业务操作日志查询成功", operationLogs);
    }

    /**
     * 根据主键ID查询操作日志详情
     * <pre>
     * 此端点根据主键ID查询单条操作日志详情，用于查看具体操作的详细信息。
     * 包括操作前数据、操作后数据、响应结果等。
     *
     * @param id 操作日志主键ID
     * @return 操作日志详情
     */
    @PostMapping("/detail/{id}")
    @ApiOperation("根据主键ID查询操作日志详情")
    public R<OperationLogDO> getOperationLogDetail(
            @ApiParam("操作日志主键ID") @PathVariable Long id) {
        log.info("根据主键ID查询操作日志详情: id={}", id);

        OperationLogDO operationLog = operationLogService.getOperationLogById(id);

        if (operationLog == null) {
            log.warn("未找到ID为 {} 的操作日志", id);
            return R.failed("操作日志不存在");
        }

        log.info("操作日志详情查询成功: {}", operationLog.getOperationDescription());
        return R.success("操作日志详情查询成功", operationLog);
    }

    /**
     * 查询操作统计信息
     * <pre>
     * 此端点查询系统的操作统计信息，包括各模块和操作类型的统计数据，
     * 用于系统监控和运营分析。默认统计最近7天的数据。
     *
     * @return 操作统计信息列表，包含模块类型、操作类型、操作次数等
     */
    @PostMapping("/statistics")
    @ApiOperation("查询操作统计信息")
    public R<List<OperationStatisticsVO>> getOperationStatistics() {
        log.info("查询操作统计信息");

        List<OperationStatisticsVO> statistics = operationLogService.getOperationStatistics();

        log.info("操作统计信息查询成功，包含 {} 项统计数据", statistics.size());
        return R.success("操作统计查询成功", statistics);
    }

    /**
     * 查询最近的操作日志
     * <pre>
     * 此端点查询系统最近的操作日志，用于首页展示或快速查看最新操作。
     * 按操作时间倒序排列。
     *
     * @param limit 查询数量限制，默认20条
     * @return 最近的操作日志列表
     */
    @PostMapping("/recent")
    @ApiOperation("查询最近的操作日志")
    public R<List<OperationLogDO>> getRecentOperations(
            @ApiParam("查询数量限制") @RequestParam(defaultValue = "20") Integer limit) {
        log.info("查询最近的操作日志，数量限制: {}", limit);

        List<OperationLogDO> recentOperations = operationLogService.getRecentOperations(limit);

        log.info("查询到 {} 条最近的操作日志", recentOperations.size());
        return R.success("最近操作日志查询成功", recentOperations);
    }

    /**
     * 根据操作人统计操作次数
     * <pre>
     * 此端点统计指定天数内各操作人的操作次数，
     * 用于分析用户活跃度和操作行为。
     *
     * @param days 统计天数，默认7天
     * @return 操作人统计信息列表
     */
    @PostMapping("/statistics/operator")
    @ApiOperation("根据操作人统计操作次数")
    public R<List<OperatorStatisticsVO>> getOperationCountByOperator(
            @ApiParam("统计天数") @RequestParam(defaultValue = "7") Integer days) {
        log.info("根据操作人统计操作次数，统计天数: {}", days);

        List<OperatorStatisticsVO> operatorStatistics = operationLogService.getOperationCountByOperator(days);

        log.info("操作人统计查询成功，包含 {} 项统计数据", operatorStatistics.size());
        return R.success("操作人统计查询成功", operatorStatistics);
    }

    /**
     * 查询详细统计信息
     * <pre>
     * 此端点查询系统的详细统计信息，包括：
     * - 今日操作数：今天的操作数量
     * - 成功操作数：全部成功的操作数量
     * - 失败操作数：全部失败的操作数量
     * - 总操作数：系统全部操作数量
     *
     * @return 详细统计信息
     */
    @PostMapping("/statistics/detailed")
    @ApiOperation("查询详细统计信息")
    public R<OperationLogStatisticsVO> getDetailedStatistics() {
        log.info("查询详细统计信息");

        OperationLogStatisticsVO detailedStats = operationLogService.getDetailedStatistics();

        log.info("详细统计信息查询成功: {}", detailedStats);
        return R.success("详细统计查询成功", detailedStats);
    }

    /**
     * 清理历史操作日志
     * <pre>
     * 此端点清理指定天数之前的历史操作日志，用于控制数据库存储空间。
     * 建议定期执行此操作，保留90-180天的日志数据即可。
     * 为安全起见，最少保留30天的日志。
     *
     * @param days 保留天数，删除该天数之前的日志
     * @return 清理的日志记录数
     */
    @PostMapping("/clean")
    @ApiOperation("清理历史操作日志")
    public R<Integer> cleanHistoryLogs(
            @ApiParam("保留天数") @RequestParam Integer days) {
        log.info("清理历史操作日志，保留天数: {}", days);

        Integer cleanedCount = operationLogService.cleanHistoryLogs(days);

        log.info("历史日志清理完成，清理记录数: {}", cleanedCount);
        return R.success("历史日志清理成功", cleanedCount);
    }
}
